package com.easyj.admin.sys.serviceimpl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.easyj.admin.sys.service.DepartmentService;
import com.easyj.admin.sys.service.RoleService;
import com.easyj.admin.sys.service.UserService;
import com.easyj.admin.activiti.utils.ProcessUtils;
import com.easyj.admin.db.mapper.GroupUserMapper;
import com.easyj.admin.db.mapper.PositionMapper;
import com.easyj.admin.db.mapper.UserMapper;
import com.easyj.admin.db.mapper.UserPositionMapper;
import com.easyj.admin.db.mapper.UserRoleMapper;
import com.easyj.base.common.imp.ImpExcutor;
import com.easyj.base.common.imp.ImpField;
import com.easyj.base.common.imp.ImpUtils;
import com.easyj.base.common.page.Page;
import com.easyj.admin.db.model.Department;
import com.easyj.admin.db.model.Group;
import com.easyj.admin.db.model.ImpResult;
import com.easyj.admin.db.model.Permission;
import com.easyj.admin.db.model.Position;
import com.easyj.admin.db.model.Role;
import com.easyj.admin.db.model.User;
import com.easyj.admin.db.model.UserPosition;
import com.easyj.admin.db.model.UserQO;
import com.easyj.admin.db.model.UserRole;
import com.easyj.base.enums.StatusEnum;
import com.easyj.base.exception.EasyjException;
import com.easyj.base.exception.ImpValidException;
import com.easyj.base.exception.UpdateSystemObjectException;
import com.easyj.base.exception.ValidateException;
import com.easyj.base.security.EasyjGrantedAuthority;
import com.easyj.base.security.SecurityConstant;
import com.easyj.base.security.UserAuthorities;
import com.easyj.base.security.service.SecurityUtil;


@Service
public class UserServiceImpl implements UserService{
    
    public final String UserAuthorities="UserAuthorities";
    
	@Autowired
	private  UserMapper userMapper;
	
	@Autowired
	private  UserRoleMapper userRoleMapper;
	
	@Autowired
	private RoleService  roleService;
	
	@Autowired
	private  UserPositionMapper userPositionMapper;
	
	@Autowired
	private  PositionMapper positionMapper;
	
	@Autowired
	private  GroupUserMapper groupUserMapper;
	
	@Autowired
	private  DepartmentService departmentService;
	
	public List<User> searchUser(String filter){	
		List<User> list=userMapper.searchUser(filter);
		if(list!=null ) {
			for(User find:list) {
			    find.setName(find.getName()+"("+find.getLoginName()+","+find.getMobile()==null?"":find.getMobile()+")");
			}		
			
		}
	    return list;
    }
	
	public Page<User> findPage(UserQO filter){
	    long total=userMapper.countByExample(filter);
		List<User> rows=null;
		if(total>0l){
			filter.getPage().resetOffsetByTotal(total);
		    rows= userMapper.selectByExample(filter);
		    //roles 用于显示
			if(rows!=null) {
				for(User u:rows){
				    u.setPassword("********");
					List<Role> roles= userRoleMapper.selectRolesByUserId(u.getId());
					u.setRoles(roles);
					List<Position> positions=userPositionMapper.selectPositionsByUserId(u.getId());
				    u.setPositions(positions);
				}
			}
		}
		
		Page<User> rtn=new Page<User>(rows,total,filter.getPage());
		return rtn;
	}
	
	public long count(UserQO filter) {
		long total=userMapper.countByExample(filter);
		return total;
	}
	
	public List<User> findList(UserQO filter){
		
	    List<User> rows= userMapper.selectByExample(filter);
	    //roles 用于显示
		if(rows!=null) {
			for(User u:rows){
			    u.setPassword("********");
				List<Role> roles= userRoleMapper.selectRolesByUserId(u.getId());
				u.setRoles(roles);
				List<Position> positions=userPositionMapper.selectPositionsByUserId(u.getId());
			    u.setPositions(positions);
			}
		}
		return rows;
	}
		

	public List<User> findAll(){
		UserQO filter=new  UserQO();
		 filter.setStatus(1);	  
		 List<User>  rows= userMapper.selectByExample(filter);
		    //roles 用于显示
			if(rows!=null) {
				for(User u:rows){
				    u.setPassword("********");	
				}
		}
		return rows;
	}
	
	public User findById(Long id){
		User entity= userMapper.selectByPrimaryKey(id);
		entity.setPassword("********");
		return entity;
	}
	
	/**
	 * 从cache 取得user
	 * @param id
	 * @return
	 */
	@Cacheable(value="users",key="#id")
	public User findByCache(Long id){
		User entity= userMapper.selectByPrimaryKey(id);
		return entity;
	}
	
	public List<Role> findRolesByUserId(Long userId){
		List<Role> rows= userRoleMapper.selectRolesByUserId(userId);
		return rows;
	}
	

	public List<Position> findPositionsByUserId(Long userId){
		List<Position> rows=userPositionMapper.selectPositionsByUserId(userId);
		return rows;
	}
	
	public List<Group> findGroupsByUserId(Long userId){
		List<Group> rows=groupUserMapper.selectGroupsByUserId(userId);
		return rows;
	}

	@Transactional
	public int  insertEntity(User entity) throws  EasyjException{
		if(userMapper.selectByLoginName(entity.getLoginName())!=null) {
			throw new ValidateException(EasyjException.SameCode,"登录账号已存在");
		}
		//真实姓名也唯一.....
		//if(selectUniqueByUqName(entity.getName())!=null) {
		//	throw new ValidateException(EasyjException.SameName,"用户"+entity.getName()+"已存在");
		//}
		if(StringUtils.isNotBlank(entity.getMobile())) {
			if(selectUniqueByMobile(entity.getMobile())!=null) {
				throw new ValidateException(EasyjException.SameMobile,"手机号："+entity.getMobile()+"已存在");
			}
						
		}else {
			entity.setMobile(null);
		}
		
		entity.setPassword(SecurityConstant.PasswordEncoder.encode(entity.getPassword())); //encode password
		
		entity.setCreateTime(new Date());
		entity.setOperatorId(SecurityUtil.getOperatorId());	
		entity.setIsSystem(false);
		entity.setLocked(false);
		entity.setLevel(0);//set default value....
		
		entity.setCreateTime(new Date());
		entity.setModifyTime(new Date());
		int rtn= userMapper.insert(entity);
		
		//roles
		if(entity.getRoleIds()!=null){
			for(Long roleId:  entity.getRoleIds()){
				UserRole r=new UserRole();
				r.setRoleId(roleId);
				r.setUserId(entity.getId());
				userRoleMapper.insert(r);
			}
		}		
		//positions 
		if(entity.getPositionIds()!=null){
			for(Long positionId:  entity.getPositionIds()){
				UserPosition r=new UserPosition();
				r.setPositionId(positionId);
				r.setUserId(entity.getId());
				userPositionMapper.insert(r);
			}
		}	
		
		return rtn;
	}

	@CacheEvict(value= {UserAuthorities,"users"}, key="#entity.id")
	@Transactional
	public int  updateEntity(User entity) throws EasyjException{
		User old= userMapper.selectByPrimaryKey(entity.getId());
	    if(old.getIsSystem()) {
	    	throw new UpdateSystemObjectException();
	    }
	    
	  //真实姓名也唯一.....
	  //  User f=selectUniqueByUqName(entity.getName());
  	   //	if(f!=null && f.getId().longValue()!=entity.getId().longValue()) {
  	   //		throw new ValidateException(EasyjException.SameName,"用户"+entity.getName()+"已存在");
  	  //	}
	    
	    if(StringUtils.isNotBlank(entity.getMobile())) {
  			User p=selectUniqueByMobile(entity.getMobile());
  			if(p!=null && p.getId().longValue()!=entity.getId().longValue()) {
				throw new ValidateException(EasyjException.SameMobile,"手机号："+entity.getMobile()+"已存在");
			}
		}else {
			entity.setMobile(null);
		}
	  		
	    entity.setModifyTime(new Date());
	    entity.setOperatorId(SecurityUtil.getOperatorId());
		int rtn= userMapper.updateByPrimaryKey(entity);
		entity.setModifyTime(new Date());
		
		//先删除用户的role,后增加
		userRoleMapper.deleteByUserId(entity.getId());
		if(entity.getRoleIds()!=null){
			for(Long roleId:  entity.getRoleIds()){
				UserRole r=new UserRole();
				r.setRoleId(roleId);
				r.setUserId(entity.getId());
				userRoleMapper.insert(r);
			}
		}
		
		//positions 
		userPositionMapper.deleteByUserId(entity.getId());
		if(entity.getPositionIds()!=null){
			for(Long positionId:  entity.getPositionIds()){
				UserPosition r=new UserPosition();
				r.setPositionId(positionId);
				r.setUserId(entity.getId());
				userPositionMapper.insert(r);
			}
		}	
		
		return rtn;
	}
	
	public User  selectUniqueByMobile(String mobile){
		   User entity= userMapper.selectUniqueByMobile(mobile);
		   return entity;
		}
	/**
	 * 用户更新自己的个人信息
	 * @param persioninfo
	 * @return
	 */
	@CacheEvict(value= "users", key="#entity.id")
	@Transactional
	public int updatePersonInfo(User entity) {
		return  userMapper.updatePersonInfo(entity);
	}
	
	@CacheEvict(value= "users", key="#entity.id")
	@Transactional
	public int updateAvatar(User entity) {
		return  userMapper.updateAvatar(entity);
	}

    @CacheEvict(value=UserAuthorities, key="#id")
	@Transactional
	public int  disableById(Long id) throws EasyjException{
	    User entity= userMapper.selectByPrimaryKey(id);
	    if(entity.getIsSystem()) {
	    	throw new UpdateSystemObjectException();
	    }
		entity.setStatus(StatusEnum.Disabled.getKey());
		entity.setModifyTime(new Date());
		entity.setOperatorId(SecurityUtil.getOperatorId());
		int rtn= userMapper.updateByPrimaryKeySelective(entity);
		return rtn;
	}
	
	@CacheEvict(value=UserAuthorities, key="#id")
	@Transactional
	public int  enableById(Long id)throws EasyjException{
	    User entity= userMapper.selectByPrimaryKey(id);
	    if(entity.getIsSystem()) {
	    	throw new UpdateSystemObjectException();
	    }
		entity.setStatus(StatusEnum.Enabled.getKey());
		entity.setModifyTime(new Date());
		entity.setOperatorId(SecurityUtil.getOperatorId());
		int rtn= userMapper.updateByPrimaryKeySelective(entity);
		return rtn;
	}
	
	@CacheEvict(value=UserAuthorities, key="#id")
	@Transactional
	public int  leaveById(Long id)throws EasyjException{
	    User entity= userMapper.selectByPrimaryKey(id);
	    if(entity.getIsSystem()) {
	    	throw new UpdateSystemObjectException();
	    }
		entity.setState(0);
		entity.setModifyTime(new Date());
		entity.setOperatorId(SecurityUtil.getOperatorId());
		int rtn= userMapper.updateByPrimaryKeySelective(entity);
		return rtn;
	}


	public User  findByLoginName(String loginName){
	   User entity= userMapper.selectByLoginName(loginName);
	   return entity;
	}
	
	//public User  selectUniqueByUqName(String name){
	//   User entity= userMapper.selectUniqueByUqName(name);
	//   return entity;
	//}
	
	@Transactional
	public int saveLoginInfo(User loginInfo) {
		int rtn= userMapper.updateLoginInfo(loginInfo);
		return rtn;
	}
	
	@Transactional
	public int changePassword(User info) {
		info.setPassword(SecurityConstant.PasswordEncoder.encode(info.getPassword()));
		int rtn= userMapper.updatePassword(info);
		return rtn;
	}
	
	
    //取用户角色权限---------	
	@Cacheable(value=UserAuthorities,key="#id")
	public UserAuthorities getUserAuthoritiesByCache(Long id,Long deptId) {
		return getAuthoritiesByUserId(id,deptId);
	}
	
	//put to cache.....
	@CachePut(value=UserAuthorities,key="#id")
	public UserAuthorities getUserAuthorities(Long id,Long deptId) {
		return getAuthoritiesByUserId(id,deptId);
	}
	
	private UserAuthorities getAuthoritiesByUserId(Long id,Long deptId) {
		Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
		//role
		List<Role> roles=findRolesByUserId(id);
		if(roles!=null && roles.size()>0) {
			List<Long> ids=new  ArrayList<Long>();
			for(Role role:roles) {
				ids.add(role.getId());
				
			}
			List<Permission> ps=roleService.findPermissionsByRoleIds(ids);
		   	if(ps!=null) {
		   		for(Permission p:ps) {
		   			if(!StringUtils.isBlank(p.getPermission())) {
		   			    authorities.add(new EasyjGrantedAuthority(p.getPermission().trim()));
		   			}
		   		}
		   	}
		}
		
		//set to list
		List<GrantedAuthority> rtnAuths=new ArrayList<GrantedAuthority>();
		rtnAuths.addAll(authorities);
		
		List<Position> positions=findPositionsByUserId(id);
		
		List<Group> groups=findGroupsByUserId(id);
		
		/* 
		  activiti7  的 ProcessRuntime、 TaskRuntime需要ACTIVITI_USER角色
		  ProcessRuntimeImpl 有 @PreAuthorize("hasRole('ACTIVITI_USER')")
		   spring sccurity 又需要Authorities 加上“ROLE_”,表示有此角色
		 */
		rtnAuths.add(new EasyjGrantedAuthority("ROLE_ACTIVITI_USER"));
		
		/**
		 * 为activiti7 处理用户组
		 * （1）角色当作activiti分组，加下后缀@role表示这个分组是从角色来的
		 * （2）岗位当作activiti分组，加下后缀@position表示这个分组是从角色来的
		 * （3）群组当作activiti分组，加下后缀@group表示这个分组是从群组来的
		 * （4）部门（不包下级部门）当作activiti分组，加下后缀@dept表示这个分组是从部门来的，一般是最小部门作为候选组
		 */
		if(roles!=null) {
			for(Role role:roles) {
				rtnAuths.add(new EasyjGrantedAuthority("GROUP_"+role.getCode()+ProcessUtils.RoleSubffix));
			}
		}
		
		if(positions!=null) {
			for(Position p:positions) {
				rtnAuths.add(new EasyjGrantedAuthority("GROUP_"+p.getCode()+ProcessUtils.PositionSubffix));
			}
		}
		
		if(groups!=null) {
			for(Group p:groups) {
				rtnAuths.add(new EasyjGrantedAuthority("GROUP_"+p.getCode()+ProcessUtils.GroupSubffix));
			}
		}
		
		if(deptId!=null) {
			Department dept=departmentService.findById(deptId);
			if(dept!=null) {
				rtnAuths.add(new EasyjGrantedAuthority("GROUP_"+dept.getCode()+ProcessUtils.DeptSubffix));
			}
		}
		
		UserAuthorities rtn=new  UserAuthorities();
		
		rtn.setAuthorities(rtnAuths);
		return rtn;
	}



	@Override
	public int unLockedUserAuto(Date loginTime) {		
		return userMapper.unLockedUserAuto(loginTime);
	}



	@Override
	public int unLockedUserById(Long id) {		
		return userMapper.unLockedUserById(id);
	}
	
	
	@Override
	public int lockedUserById(Long id) {		
		return userMapper.lockedUserById(id);
	}
	
	/**
	 * import from excel
	 * @param excelfile
	 * @param operatorId
	 * @return
	 * @throws Exception
	 */
	public ImpResult importExcel(MultipartFile excelfile,Long operatorId) throws Exception{
		ValidatorFactory factory=Validation.buildDefaultValidatorFactory();
		final Validator validator =factory.getValidator(); 
		ImpExcutor<User> impExcutor=new ImpExcutor<User>("用户",operatorId){

				@Override
				protected User getAndValidateBean(Row row) throws ImpValidException {
					HashMap<String,String> errmap=new HashMap<String,String>();
					//set bean value
					User bean=new User();
					bean.setStatus(1); //status-----
					//直接设值
					//ImpUtils.setObjectValueByRow(row, fields, bean);
					//设值，对分类特别处理
					
					String  departmentName=null;
					String departmentCode=null;
					for(ImpField f :fields){
						Cell cell=row.getCell(f.getPosition());
						if(cell==null){
							continue;
						}
						try {
							if(f.getName().equals("departmentName")) {
								departmentName=(String)ImpUtils.getCellValue(cell,f);
							}else if(f.getName().equals("departmentCode")) {
								departmentCode=(String)ImpUtils.getCellValue(cell,f);
							}
							else if(f.getPosition()!=null){
				                Object value=ImpUtils.getCellValue(cell,f);
								PropertyUtils.setProperty(bean, f.getName(),value);
							}
						}catch(Exception ex) {
							errmap.put(f.getName(), "数据不符合规范，取值失败");
						}
					}
					
					if(errmap.size()>0) {
						throw new ImpValidException("取值失败",errmap);
					}
					
					//get deptId...
					if(StringUtils.isNotBlank(departmentCode)) {
						Department ps= departmentService.selectUniqueByUnique(departmentCode);
						 if(ps==null) {
							 errmap.put("useDeptCode", "所属部门编码不存在");
						 }else {
							 bean.setDepartmentId(ps.getId());
						 }
					}else if(StringUtils.isNotBlank(departmentName)){
						Department filter=new Department();
						filter.setName(departmentName);
						filter.setDeleted(false);
						List<Department> ls=departmentService.findList(filter);
						if(ls==null||ls.size()==0) {
							errmap.put("deptName", "所属部门不存在");
						}else if(ls.size()==1) {
							bean.setDepartmentId(ls.get(0).getId());
						}else {
							errmap.put("deptName", "所属部门有相同名称");
						}	
					}else  {
						errmap.put("useDeptCode", "请输入所属部门编码或名称");
					}
					
					if(StringUtils.isNotBlank(bean.getPositionsName())){
						Position ls=positionMapper.selectUniqueByUqName(bean.getPositionsName());
						if(ls==null) {
							errmap.put("positionsName", "岗位不存在");						
						}else {
							ArrayList<Long> pids=new ArrayList<Long>();
							pids.add(ls.getId());
							bean.setPositionIds(pids);
						}	
					}else  {
						errmap.put("positionsName", "岗位必填");
					}
					
					if(StringUtils.isNotBlank(bean.getRolesName())){
						Role r=roleService.selectUniqueByUqName(bean.getPositionsName());
						if(r==null) {
							errmap.put("rolesName", "角色不存在");						
						}else {
							ArrayList<Long> pids=new ArrayList<Long>();
							pids.add(2l); //default =2
							if(r.getId()!=2) {
							  pids.add(r.getId());
							}
							bean.setRoleIds(pids);
						}	
					}else {
						ArrayList<Long> pids=new ArrayList<Long>();
						pids.add(2l); //default =2
						bean.setRoleIds(pids);
					}
					
					//password 
					if(StringUtils.isBlank(bean.getPassword())
							||bean.getPassword().length()<6) {
						errmap.put("password", "密码不符合要求");	
						
					}
					
					//valid
					Set<ConstraintViolation<User>> constraintViolations = validator.validate(bean);
					if(CollectionUtils.isNotEmpty(constraintViolations)){
						for(ConstraintViolation<User> e:constraintViolations){
							if(e.getPropertyPath()!=null){
								errmap.put(e.getPropertyPath().toString(), e.getMessage());
							}
						}
						
					}
					
					
					//has error then throw excepton
	                if(errmap.size()>0) {
	                	throw new ImpValidException("数据不符合规范",errmap);
	                }
					//default status
	                bean.setState(1);
	                bean.setStatus(1);
					return bean;
				}
	
				@Override
				protected int save(User bean) throws Exception{
					try {
					  bean.setOperatorId(operatorId);	
					  return insertEntity(bean);	
					}catch(ValidateException e ) {
						HashMap<String,String> errmap=new HashMap<String,String>();
						errmap.put("loginName",  e.getMessage());
						throw new ImpValidException("",errmap);
					}
				}
		};
		
		ImpResult rtn=impExcutor.initImport(excelfile, "user.xml");
		
		//异步导入
		runImportData(impExcutor);
		return rtn;
	}
	 @Async
	private void runImportData(ImpExcutor<User> excutor) {
		excutor.execImport();
	}
			
	
}
